/*
 * 软件版权: 恒生电子股份有限公司
 * 修改记录:
 * 修改日期     修改人员  修改说明
 * ========    =======  ============================================
 * 2021/3/31  lisy31662  新增
 * ========    =======  ============================================
 */
package com.sansi.pencilbook.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * 功能说明: 推荐工具
 *
 * @author lisy31662
 */
public class RecommendUtil {

  public static double getInterest() {
    return 0.0;
  }

  /**
   * 去除某个值一次后获取平均分(去除0值)
   * @param score
   * @return
   */
  public static double getAvgScore(double[] score, double unScore) {
    double sum = 0.0;
    int length = score.length;
    for (int i=0;i<score.length;i++) {
      if (score[i]==0.0)
        length--;
      else if (score[i]==unScore) {
        length--;
        unScore=0.0;
      }
      else
        sum+=score[i];
    }
    return sum/length;
  }

  /**
   * 获取平均分(去除0值)
   * @param score
   * @return
   */
  public static double getAvgScore(double[] score) {
    double sum = 0.0;
    int length = score.length;
    for (int i=0;i<score.length;i++) {
      if (score[i]==0.0)
        length--;
      else
        sum+=score[i];
    }
    return sum/length;
  }

  public static double getSimilarity(double[] user1Score, double[] user2Score) {
    return validData(user1Score, user2Score);
  }

  /**
   * 获取score和otherScore的所有相似度
   * @param otherScore
   * @param score
   * @return
   */
  public static double[] getSimilarities(double[][] otherScore, double[] score) {
    double[] similarities = new double[otherScore.length];
    for (int i=0;i<otherScore.length;i++) {
      similarities[i] = getSimilarity(otherScore[i], score);
    }
    return similarities;
  }

  /**
   * 在所有分数中，给出用户下标，计算相似度
   * @param allScore
   * @param userId
   * @return
   */
  public static double[] getSimilarities(double[][] allScore, int userId) {
    double[] similarities = new double[allScore.length-1];
    for (int i=0;i<allScore.length-1;i++) {
      if (i==userId)
        continue;
      similarities[i] = getSimilarity(allScore[i], allScore[userId-1]);
    }
    return similarities;
  }

  /**
   * 根据皮尔逊相似度计算
   * @param user1Score
   * @param user2Score
   * @return
   */
  public static double getSimilarity(List<Double> user1Score, List<Double> user2Score) {
    Double[] userScore1 = user1Score.toArray(new Double[user1Score.size()]);
    Double[] userScore2 = user2Score.toArray(new Double[user2Score.size()]);
    double avg1 = sum(userScore1)/Math.max(userScore1.length,1);
    double avg2 = sum(userScore2)/Math.max(userScore2.length,1);
    double vector1 = 0.0;
    double vector2 = 0.0;
    double numerator = 0.0;
    for (int i=0;i<userScore1.length;i++) {
      numerator += (userScore1[i]-avg1) * (userScore2[i]-avg2);
      vector1 += Math.pow(userScore1[i]-avg1, 2);
      vector2 += Math.pow(userScore2[i]-avg1, 2);
    }
    return numerator/(Math.sqrt(vector1)*Math.sqrt(vector2));
  }

  public static double sum(Double[] array) {
    double sum = 0.0;
    for (double num : array) {
      sum += num;
    }
    return sum;
  }

  public static double validData(double[] user1Score, double[] user2Score) {
    List<Double> score1 = new ArrayList<>();
    List<Double> score2 = new ArrayList<>();
    for (int i=0;i<user1Score.length;i++) {
      if (user1Score[i]!=0 && user2Score[i]!=0) {
        score1.add(user1Score[i]);
        score2.add(user2Score[i]);
      }
    }
    return getSimilarity(score1, score2);
  }

}
